﻿using System;
using FluentAssertions;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using O1.Kernel;
using O1.Kernel.Primitives;

namespace Tests.O1.Kernel.Primitives
{
    [TestClass]
    public class DecimalPropertyTests
    {
        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyWritesDataIntoPackedSizeBufferAsExpected()
        {
            var subject = new DecimalProperty(6, 122.88m);
            var buffer = new byte[DecimalProperty.Size];
            subject.Write(buffer, 0);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyWritesDataValuesAsExpected()
        {
            var subject = new DecimalProperty(99, 12200.986m);
            var buffer = new byte[DecimalProperty.Size];
            subject.Write(buffer, 0);

            var actualValue = buffer.ToDecimal(0);
            var actualKey = BitConverter.ToInt32(buffer, 16);

            actualValue.Should().Be(12200.986m);
            actualKey.Should().Be(99);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyReadsAsExpected()
        {
            var buffer = new byte[DecimalProperty.Size];
            (12345.678m).CopyBytes(buffer, 0);
            var key = BitConverter.GetBytes(77);
            Array.Copy(key, 0, buffer, Sz.CLR.Decimal, 4);

            var subject = DecimalProperty.Read(buffer, 0);
            subject.Key.Should().Be(77);
            subject.Value.Should().Be(12345.678m);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyWritesThenReadsAsExpected()
        {
            var expected = new DecimalProperty(99, 12200);
            var buffer = new byte[DecimalProperty.Size];
            expected.Write(buffer, 0);

            var actual = DecimalProperty.Read(buffer, 0);
            actual.Key.Should().Be(expected.Key);
            actual.Value.Should().Be(expected.Value);
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyEqualityIsKeyValueEquality()
        {
            var subject1 = new DecimalProperty(99, 12200);
            var subject2 = new DecimalProperty(99, 12200);
            (subject1 == subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyInequalityIsKeyInequality()
        {
            var subject1 = new DecimalProperty(99, 12200);
            var subject2 = new DecimalProperty(98, 12200);
            (subject1 != subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyInequalityIsValueInequality()
        {
            var subject1 = new DecimalProperty(98, 4500);
            var subject2 = new DecimalProperty(98, 12200);
            (subject1 != subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyEqualsIsValueEquality()
        {
            var subject1 = new DecimalProperty(99, 12200);
            var subject2 = new DecimalProperty(99, 12200);
            subject1.Equals(subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyEqualsIsKeyInequality()
        {
            var subject1 = new DecimalProperty(99, 12200);
            var subject2 = new DecimalProperty(98, 12200);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyEqualsIsValueInequality()
        {
            var subject1 = new DecimalProperty(98, 1200);
            var subject2 = new DecimalProperty(98, 12200);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyIsNotEqualToNull()
        {
            object other = null;
            new DecimalProperty(98, 1200).Equals(other).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyGetHashCodeIsConsistent()
        {
            var subject = new DecimalProperty(98, 1500);
            subject.GetHashCode().Should().Be(subject.GetHashCode());   
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyGetHashCodeIsDifferentForDifferentKey()
        {
            var subject1 = new DecimalProperty(98, 12500);
            var subject2 = new DecimalProperty(101, 12500);
            subject1.GetHashCode().Should().NotBe(subject2.GetHashCode());
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyGetHashCodeIsDifferentForDifferentValue()
        {
            var subject1 = new DecimalProperty(101, 12500);
            var subject2 = new DecimalProperty(101, 1200);
            subject1.GetHashCode().Should().NotBe(subject2.GetHashCode());
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyGetHashCodeIsDifferentForDifferentKeyAndValue()
        {
            var subject1 = new DecimalProperty(88, 14500);
            var subject2 = new DecimalProperty(101, 1200);
            subject1.GetHashCode().Should().NotBe(subject2.GetHashCode());
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyObjectEqualsIsEquality()
        {
            var subject1 = new DecimalProperty(98, 12400);
            object subject2 = new DecimalProperty(98, 12400);
            subject1.Equals(subject2).Should().BeTrue();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyObjectEqualsIsInequalityForDifferentKey()
        {
            var subject1 = new DecimalProperty(99, 12400);
            object subject2 = new DecimalProperty(98, 12400);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyObjectEqualsIsInequalityForDifferentValue()
        {
            var subject1 = new DecimalProperty(99, 12500);
            object subject2 = new DecimalProperty(99, 500);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyObjectEqualsIsInequalityForDifferentKeyAndValue()
        {
            var subject1 = new DecimalProperty(8769, 14500);
            object subject2 = new DecimalProperty(99, 500);
            subject1.Equals(subject2).Should().BeFalse();
        }

        [TestMethod, TestCategory("Unit Test")]
        public void DecimalPropertyObjectEqualsIsInequalityForDifferentType()
        {
            var subject1 = new DecimalProperty(99, 14500);
            object subject2 = new object();
            subject1.Equals(subject2).Should().BeFalse();
        }
    }
}
